Fundamentos de Web Scraping con Python y Xpath

Objetivos

Tabla de contenido

Fundamentos de Web Scraping con Python y Xpath

Introducción al web scraping

¿Qué es el web scraping?

web_scrapping

Web scraping es una técnica usada por data scientists y backend developers para extraer información de internet, accede a esto usando el protocolo de tranferencias de hipertexto (HTTP) o a través de un navegador. Los datos extraídos usualmente son guardados en una base de datos, incluso en una hoja de cálculo para posteriores análisis. Puede hacerse de manera automática (bot) o manualmente.

Xpath es un lenguaje que sirve para apuntar a las partes de un documento XML. Xpath modela un documento XML como un árbol de nodos. Existen diferentes tipos de nodos: elementos, atributos, texto.

¿Por qué aprender web scraping hoy?

Las agencias de seguridad, aplicaciones que comparan precios más baratos entre hoteles, apliaciones de ecommerce que comparan precios entre diferentes competidores usan web scraping. Las agencias de marketing para analziar el contenido de tweets que se vuelven virales. En general el web scraping es una habilidad muy valiosa para cuando no tienes acceso a una API.

Es posible realizar web scraping con diferentes lenguajes de programación, como R o Js (y sus respectivas librerías) sin embargo Py es por excelencia el lenguaje de programación para esta tarea. Cuenta con la comunidad más grande para implementarlo.

Python: el lenguaje más poderoso para extraer datos

Python es el lenguaje que mas soporte tiene en el mundo open source y en general para realizar este tipo de técnicas. Existen una cantidad de módulos para realizar por ti mismo web scrapping. Python es uno de los lenguajes que esta mas especializado para hacer ciencia de datos. Por lo tanto para los cienctificos de datos esto es una ventaja grande. Si eres backend developer y trabajas con Django puedes nuclear el conocimiento de web scraping con Django y realizar un proyecto sin irse de lenguaje en lenguaje.

Principales frameworks(librerias) en python

Herramientas de web scrapping

Los siguientes son soluciones que no necesitan codear, y que en su mayoría tienen un propósito específico. Enfocados ecomerce o a funciones como tomar screenshots de PDFs. Automatizar y agendar actividades, y las soluciones están dadas como pluggins en el navegador hasta servicios.

Otras librerais y otros lenguajes

Fundamentos de la web

Entender HTTP

El protocolo HTTP es conjunto de reglas por el cual dos computadoras se comunican. Un cliente y un servidor. El cliente realiza peticiones a servidores.

Una petición se vería de la siguiente manera:

# Request
GET / HTTP/1.1
Host: developer.mozilla.org  Accept-Language: fr

# Response  
HTTP/1.1 200 OK
Date: Sat, 09 Oct 2010 14:28:02 GMT
Server: Apache
Last-Modified: Tue, 01 Dec 2009 20:18:22 GMT  ETag: "51142bc1-7449-479b075b2891b"
Accept-Ranges: bytes  Content-Length: 29769  Content-Type: text/html
<!DOCTYPE html... (here comes the 29769 bytes of the  requested web page)

HEADERS

Permiten al cliente y el servidor passar información adicional con un request o response HTTP.

Pueden agruparse en las siguientes categorías:

Existen muchas cabeceras o headers como:

Puedes consultar aquí toda la documentación sobre las cabeceras o Headers

HTTP nos permite transportar, HTML, CSS, webAPIs, Js. Se vale de protcolos como IP, TCP, UDP para comunicarse con el servidor, mediante TLS se hace la encriptación. Y el DNS asigna nombres a direcciones IP.

protocolos_web

STATUS CODE:

Los estados son la forma en que el servidor da respuesta de las peticiones.

  1. Respuestas informativas (100–199).
  2. Respuestas satisfactorias (200–299).
  3. Redirecciones (300–399).
  4. Errores de los clientes (400–499).
  5. Errores de los servidores (500–599).

Documentación de Mozilla sobre STATUS CODE

MANEJO DE STATUS CODES

Una opción rápida para manejar los STATUS CODE es usar la librería Request.

  1. Abre un ambiente virtual.
  2. En la carpeta de trabajo: pip install request

Luego en pyhton:


# Una idea sobre el manejo de los status Code.

import requests

response_platzi = requests.get('https://api.platzi.com')
print(response_platzi)
# <Response [404]>

if response_platzi.status_code == 200:
    print("Aquí tienes lo que buscas")
elif response_platzi.status_code == 400:
    print("Ups, no puedo darte nada en el momento. Nosotros nunca paramos de mejorar <3")

Un artículo para profundizar en cómo manejar la librería request y como manejar los status code Request Tutorial

¿Qué es HTML?

HTML es una lenguaje que permite definir la estructura de una página web. Estrucutra, estilo, partes interactivas. En el contexto de webscraping HTML es muy importante.

Etiquetas está encerrado en angle brakets < >. Una etiqueta puede contener a otras etiquetas, las etiquetas tienen atributos.

El conocimiento de los atributos es crucial porque con ellos podremos conectar el scraper para extraer información.

La siguientes etiquetas son importantes para el web scraping y por ende se explican:

Robots.txt: permisos y consideraciones al hacer web scraping

Los archivos robots.txt exiten como una forma de administrar una página web. Proporciona información a los rastreadores de los buscadores sobre las páginas o los archivos que pueden solicitar o no de tu sitio web. Principalmente, se utiliza para evitar que tu sitio web se sobrecargue con solicitudes.

En el contexto de webscraping, le dice al scraper que puede y no extraer. Es decir hasta donde puede llegar. Ya que infrigir en la violación de estas directivas puede acarrear un problema legal con el sitio web al que estamos scrapeando.

robots.txt Contiene entre otros elementos:

USER-AGENT: Identificadores de quienes acceden a tu sitio web, puede ser un archivo.py hasta un googlebot.

DIRECTIVAS


Ejemplo:

url/robots.txt
Por ejemplo:

# Robots.txt file from http://www.nasa.gov
#
# All robots will spider the domain

User-agent: *
Disallow: /worldbook/
Disallow: /offices/oce/llis/


Para conocer más información de robots.txt.


Resumen de la sección anterior para introducirnos en la siguiente:

Se aprendio como esta conformada la estructura de un sitio web.

Sabemos que es HTTP, el protocolo de transferencia de hipertexto, el cual nos permite comunicar un cliente y un servidor en la red. En esta comunicación el servidor nos envia un documento de tipo HTML.

En este documento se define la estructura de un sitio web. Sabemos como esta conformada esta estructura y como contruir una.

Se analizo el archivo robots.txt, el cual define las reglas para poder extrar información o no, dependiendo sea el caso, de un sitio web.

Sabiendo lo anterior veremos Xpath, XML Path Language.

XML Path Language

XML Path Language, ¿Que es?

XML, Xtensible markup lenguage. Sirvio para definir interfaces, es un lenguaje de nodos o etiquetas.

Una técnica para extraer datos de allí es Xpath.

Xpath es a HTML lo que las REGEX son a un texto.

Es decir, Xpath es un lenguaje de patrones, expresiones que nos permitirá extraer datos de un HTML, ya que HTML y XML son muy parecidos. Puntualmente sirve para apuntar a partes de un documento XML.

Tipos de nodos en XPath

Un nodo es lo mismo que la etiqueta y su contenido. Cuando hablemos de nodos nos estaremos refiriendo a una etiqueta HTML y todo lo que contiene dentro de si misma. Un nodo puede contener a otros nodos.

En otras palabras Xpath es un lenguaje que nos permitirá movernos entre nodos y navegar en los diferentes niveles de profundidad deseados con el fin extraer información. Para describir los nodos y relaciones con Xpath se usan una sintaxis de ejes.

Toscrape es un sandbox para practicar scraping.

El siguiente esquema es un arbol de nodos con el que se trabajará para hacer scraping del sandbox toscrape.

arbol_de_nodos

Expresiones en XPath

Para escribir expresiones se usara lo siguiente $x(''). Entre las comillas se van a escribir las expresiones, las expresiones tienen diferentes símbolos que tienen una utilidad.

//Fuente de trabajo Quotes to Scrape:

url ="http://quotes.toscrape.com/"

//Voy a la consola de modzilla y hago lo siguiente.

//Quiero extraer el texto de mi nodo h1.

$x('//h1/a/text()').map(x => x.wholeText)
//Devuelve en consola: ["Quotes to Scrape"]
//La función map pertenece a Js y la estoy usando
//para que me muestre todo el texto de la selección de Xpath.

Predicados en Xpath

Cuando necesitamos un numero especifico dentro ese numero de nodos podemos utilizar [ ] como si fuera una lista, entonce llamamos el numero en el que esta ordenado esa etiqueta.

Ejemplo de los anterior en la siguiente imagen: ejemplo_predicados

Operadores en Xpath

Hay una forma de filtrar más avanzada y es con operadores lógicos.

Operadores lógicos en Xpath : Cabe notar que los operadores se usan dentro del predicado.

Ejemplo:

$x('//span[@class!="text"]')
$x('//span[@class="text" and @class="tag-item"]')

$x('//span[@class="text" or @class="tag-item"]')
$x('//span[not(@class)]')

Wildcards en Xpath

Son comodines que usamos cuando no tenemos claro lo que queremos extraer.

Ejemplos:

node() a diferencia de * trae no solamente los nodos, sino también todo el contenido.

In-text search en Xpath

Para buscar cadenas de caracteres especificas dentro de un texto.

Los ejemplos son sobre la pagina de prueba topscrape.

Ejemplo, busca todos los nodos de tipo small (//small), que cumplan clase “author” y empiecen con “A” (el . inicial es para buscar en el nodo actual), luego /text() para que nos devuelva el texto encontrado y con map lo podamos ver de manera textual.

$x('//small[@class="author" and starts-with(.,"A")]/text()').map(x => x.wholeText)

//Devuelve (4) ["Albert Einstein", "Albert Einstein", "Albert Einstein", "André Gide"]

Ejemplo, con contains trae todos los autores que tengan en su nombre “Ro”:

$x('//small[@class="author" and contains(., "g")]/text()').map(x => x.wholeText)

//Devuelve ["J.K. Rowling"]

Nota: Debido a las versiones del lenguaje Xpath en los navegadores, 1.0, las funciones end-with y matches no están disponibles, pero una en código con python corren sin problemas.

XPath Axes

Un eje representa una relación entre el nodo actual. Es usado para localizar nodos relativos a el nodo en el DOM tree.

axes

Ejemplo de utilización:

$x('/html/body/div/self::div')
$x('/html/body/div/descendant-or-self::div')

Resumen de Xpath

resumen_xpath

Aplicando lo aprendido

En el siguiente enlace, catálogos de libros, se hará scraping:


$x('//article[@class="product_pod"]/h3/a/@title').map(x => x.value)

// Salida
// Array(20) [ "A Light in the Attic", "Tipping the Velvet", "Soumission", "Sharp Objects", "Sapiens: A Brief History of Humankind", "The Requiem Red", "The Dirty Little Secrets of Getting Your Dream Job", "The Coming Woman: A Novel Based on the Life of the Infamous Feminist, Victoria Woodhull", "The Boys in the Boat: Nine Americans and Their Epic Quest for Gold at the 1936 Berlin Olympics", "The Black Maria", … ]


$x('//article[@class="product_pod"]/div[@class="product_price"]/p[@class="price_color"]/text()').map(x => x.wholeText)

// Salida
// Array(20) [ "£51.77", "£53.74", "£50.10", "£47.82", "£54.23", "£22.65", "£33.34", "£17.93", "£22.60", "£52.15", … ]


$x('//div[@class="side_categories"]/ul[@class="nav nav-list"]/li/ul/li/a/text()').map(x => x.wholeText)

// Salida
// Array(50) [ "\n                            \n                                Travel\n                            \n                        ", "\n                            \n                                Mystery\n                            \n                        ", "\n                            \n                                Historical Fiction\n                            \n                        ", "\n                            \n                                Sequential Art\n                            \n                        ", "\n                            \n                                Classics\n                            \n                        ", "\n                            \n                                Philosophy\n                            \n                        ", "\n                            \n                                Romance\n                            \n                        ", "\n                            \n                                Womens Fiction\n                            \n                        ", "\n                            \n                                Fiction\n                            \n                        ", "\n                            \n                                Childrens\n                            \n                        ", … ]

En el siguiente enlace, libro del catalogo, se hará scraping:


$x('//article[@class="product_page"]/p/text()').map(x => x.wholeText)

//Salida
//Array [ "It's hard to imagine a world without A Light in the Attic. This now-classic collection of poetry and drawings from Shel Silverstein celebrates its 20th anniversary with this special edition. Silverstein's humorous and creative verse can amuse the dowdiest of readers. Lemon-faced adults and fidgety kids sit still and read these rhythmic words and laugh and smile and love th It's hard to imagine a world without A Light in the Attic. This now-classic collection of poetry and drawings from Shel Silverstein celebrates its 20th anniversary with this special edition. Silverstein's humorous and creative verse can amuse the dowdiest of readers. Lemon-faced adults and fidgety kids sit still and read these rhythmic words and laugh and smile and love that Silverstein. Need proof of his genius? RockabyeRockabye baby, in the treetopDon't you know a treetopIs no safe place to rock?And who put you up there,And your cradle, too?Baby, I think someone down here'sGot it in for you. Shel, you never sounded so good. ...more" ]


$x('//article[@class="product_page"]//p[@class="instock availability"]/text()').map(x => x.wholeText)

// Salida
// Array [ "\n    ", "\n    \n        In stock (22 available)\n    \n" ]

Proyecto: scraper de noticias

Un proyecto para tu portafolio: scraper de noticias

Este proyecto es un scraper de noticias del diario La Republica. Vamos a extraer de este periodico, encabezados y cuerpo de las noticias diariamente y almancenarlos para un posterior análisis. Como análisis de Texto, marketing, análisis de sentimientos y demás.

Nota: Hay que observar https://www.larepublica.co/robots.txt para tener claro a qué podemos o no acceder con nuestro scraper

Entorno de trabajo

Es necesario tener buenas prácticas para desarrollar, en python como todo lenguaje tiene sus propias. A continuación la configuración inicial de este proyecto.

  1. Creamos una carpeta para el proyecto. En este caso larepublica_scraper

  2. Iniciamos git con git init. Si lo ya tenemos iniciado, no lo hacemos.

  3. Creamos el entorno virtual es: $ python3 -m venv venv (Linux) $ py -m venv venv (Windows) El ultimo venv es el nombre del entorno.

  4. Creamos el archivo .gitignore porque no queremos trackearlo, ya que seria bastante pesado llevarlo al control de versiones. Escribimos en él la carpeta /venv

  5. Activamos nuestro entorno virtual desde consola con:

    $ ven\Scripts\activate (Windows) $ source venv/bin/activate (Linux)

  6. Si trabajas en VsCode. Creamos un Workspace para tener una estructura más organizada “save as workspace” y así tener un workspace para que VS tenga idea de qué tenemos en esta capeta.

  7. Instalamos las dependencias de este proyecto:

    $ pip install requests lxml autopep8

Construcción de las expresiones de XPath

En esta sección lo que se hace es contruir las expresiones de XPath. Lo que se hace es navegar a través de la pagina, y buscar los elementos adecuados para armar las mismas. Las empresiones quedan como sigue:

//Links
$x('//div/a[contains(@class, "kicker")]/@href').map(x => x.wholeText)
//Titulo
$x('//div[@class="mb-auto"]/h2/a/text()').map(x => x.wholeText)
//Resumen
$x('//div[@class="lead"]/p/text()').map(x => x.wholeText)
//Autor
$x('//div[@class="autorArticle"]/p/text()').map(x => x.wholeText)
//Cuerpo
$x('//div[@class="html-content"]/p[not(@class)]/text()').map(x => x.wholeText)

Una vez probadas las expresiones y obteniendo la información que queremos desde la consola del navegador lo único que extraemos de las lineas de código son las expresiones xpath para utilizarlas en la sección siguiente junto con python.

Lo que haremos en esta sección, ya del proyecto del scraper, es obtener todos los links con python.

Definimos dos funciones iniciales:

Script para obtener los links: scraper.py

Debemos tener en cuenta lo siguiente a la hora de realizar el código, estos son errores Asociados y comentarios:

  1. Primera recomendación es que uses el print statement para debuggear tus código línea por línea. Es una práctica que resulta muy útil.

  2. ¿Tienes una lista vacía?, ¿No te trae los links al ejecutar scraper.py, pero tu expresion Xpath retorna en la consola de Chrome lo que buscas?.

Guardando las noticias en archivos de texto

Script donde guardamos las noticias en archivos de texto: scraper.py

Vamos a realizar una lógica para ir de cada link al sitio de cada noticia y de ahí extraer:

Esto lo haremos creando una función aparte llamada: